クラス (詳細版)
クラスは変数と関数をひとつにまとめたものです。
クラスを定義するときにはclassに続けてクラス名を記述します。
code:python
class クラス名:
def __init__(self):
初期化処理
def 処理1(self):
処理1の内容
def 処理2(self):
処理2の内容
メソッドとインスタンス変数
クラス内にはdefで関数を定義することができ、この関数を メソッド(method) と 呼びます。
次のようなクラスを見てみましょう。
code: sample_calc.py
class calc:
def __init__(self, a, b):
self.a = a
self.b = b
def add(self):
return(self.a + self.b)
def sub(self):
return(self.a - self.b)
c = calc(10, 5)
print(c.add())
print(c.sub())
d = calc(2, 3)
print(d.add())
print(d.sub())
ここで作った calcクラスは与えた2つの数値の足し算、引き算を行うものです。
Python では __init__() という名前のメソッドはクラスの初期化時に呼び出される決まりになっています。この特別なメソッドをコンストラクタ(constructor) と呼びます※。コンストラクタの中に初期化処理を書きます。
※より正確に イニシャライザ(initializer) と呼ぶこともあります。
上記の例では、10と5を与えてクラスからその実体である c を作っています。c のことを「クラス calc のインスタンス(instance)」と呼びます。インスタンスはいくつでも作ることができます。
クラスのメソッドのひとつ目の引数にはインスタンス自身を表す self を記述します。インスタンスが持つ変数にはself.変数名とすることでアクセスすることできます。 この変数をインスタンス変数(instance variable) と呼びます。
もう少し複雑な例をみてみましょう。
code:sample_book1.py
class Book:
"""本を表すクラス"""
def __init__(self, title, author):
"""コンストラクタ"""
self.title = title
self.author = author
self.pages = []
def append_page(self, text):
"""本にページを追加"""
self.pages.append(text)
def print_page(self, page_no):
"""本のページを表示"""
# 存在しないページが指定された時は何もしない
if page_no < 0 or len(self.pages) <= page_no:
return
このBookクラスは本を表現したクラスでページを追加したり、ページの内容を表示したりできます。
Bookクラスの使用例をみてみましょう。
code:sample_book1.py
# 1冊目の本をインスタンス化
my_diary = Book("日記", "me")
print("この本のタイトルは「" + my_diary.title + "」です。")
my_diary.append_page("日記の最初のページです。")
my_diary.append_page("日記の2ページ目です。")
my_diary.print_page(0)
# 2冊目の本をインスタンス化
my_notebook = Book("メモ帳", "me")
print("この本のタイトルは「" + my_notebook.title + "」です。")
my_notebook.append_page("メモ帳の最初のページです。")
my_notebook.print_page(0)
code:ouput
この本のタイトルは「日記」です。
日記の最初のページです。
この本のタイトルは「メモ帳」です。
メモ帳の最初のページです。
クラスの継承
継承を使うとクラスに機能を追加して新たなクラスを作ることができます。
classに続けてクラス名を記述し、さらに丸かっこで囲んで継承元のクラスを指定します。
継承先のクラス内ではsuper()を使うことで継承元のクラスにアクセスできます。
継承先のクラスでは継承元のクラスのメソッドを上書きすることができます。これをオーバーライド(override) と呼びます。
code:sample_book2.py
class LockableBook(Book):
"""カギをかけられる本を表すクラス"""
def __init__(self, title, author):
"""コンストラクタ"""
super().__init__(title, author)
self.locked = False
def lock(self):
"""本に鍵をかける"""
self.locked = True
def unlock(self):
"""本の鍵を外す"""
self.locked = False
def print_page(self, page_no):
"""print_pageをオーバーライド"""
# 鍵がかけられている時はページを表示しない
if self.locked:
print("鍵がかけられているので読めません。")
return
super().print_page(page_no)
継承先のクラスで定義されていないメソッドを呼び出すと、自動的に継承元のクラス内を探して実行されます。
code:sample_book2.py
my_lockable_diary = LockableBook("鍵付きの日記", "me")
# LockableBookではappend_page()を定義していないが、Bookで定義しているのでそれが実行される
my_lockable_diary.append_page("鍵付きの日記の最初のページです。")
my_lockable_diary.append_page("鍵付きの日記の2ページ目です。")
# 鍵をかける
my_lockable_diary.lock()
my_lockable_diary.print_page(0)
# 鍵を外す
my_lockable_diary.unlock()
my_lockable_diary.print_page(0)
code:output
鍵がかけられているので読めません。
鍵付きの日記の最初のページです。
なぜ継承で機能を追加するのか?
継承を使わずに元クラスをコピーし、機能を書き加えて新しいクラスを作ればいいと思うかもしれません。
継承の長所のひとつはソースコードの重複が少なくなり、変更が簡単になることです。